package fr.imag.ufrima.ima.project.core;

import org.apache.log4j.Logger;

public class Filter {
	private static Logger logger = Logger.getLogger(Filter.class);			
	private int size;
	private float[] filter;

	public static final float[] MOYENNE3x3 = {
		1/9f, 1/9f, 1/9f,
		1/9f, 1/9f, 1/9f,
		1/9f, 1/9f, 1/9f
	};
	
	public static final float[] GAUSS3x3 = {
		1/16f, 2/16f, 1/16f,
		2/16f, 4/16f, 2/16f,
		1/16f, 2/16f, 1/16f
	};
	
	public static final float[] REHAUSSE3x3 = {
		-1/26f, -1/26f, -1/26f,
		-1/26f, 18/26f, -1/26f,
		-1/26f, -1/26f, -1/26f
	};
	
	public static final float[] FLOU3x3 = {
		0.1f, 0.1f, 0.1f,
		0.1f, 0.2f, 0.1f,
		0.1f, 0.1f, 0.1f
	};	
	
	public static final float[] ACCENTUATION3x3 = {
		0.f, -1.f,  0.f,
		-1.f,  5.f, -1.f,
		0.f, -1.f,  0.f
	};

	public static final float[] LAPLACIEN_3x3 = { 
		-1.f, -1.f, -1.f, 
		-1.f, 8.f, -1.f, 
		-1.f, -1.f, -1.f 
	};
	
	public static final float[] SOBEL1_3x3 = { 
		1.f, 0.f, -1.f, 
		2.f, 0.f, -2.f, 
		1.f, 0.f, -1.f 
	};
	
	public static final float[] SOBEL2_3x3 = { 
		1.f, 2.f, 1.f, 
		0.f, 0.f, 0.f, 
		-1.f, -2.f, -1.f 
	};
	
	public static float[] getFilterByKey(int key) {
		switch(key) {
			case 0: logger.info(String.format("Filter MOYENNE3X3 selected.")); 
					return Filter.MOYENNE3x3;
			case 1: logger.info(String.format("Filter GAUSS3x3 selected."));
					return Filter.GAUSS3x3;
			case 2: logger.info(String.format("Filter REHAUSSE3x3 selected."));
					return Filter.REHAUSSE3x3;
			case 3: logger.info(String.format("Filter FLOU3x3 selected."));
					return Filter.FLOU3x3;
			case 4: logger.info(String.format("Filter ACCENTUATION3x3 selected."));
					return Filter.ACCENTUATION3x3;
			case 5: logger.info(String.format("Filter LAPLACIEN_3x3 selected."));
					return Filter.LAPLACIEN_3x3;
			
			default: logger.info(String.format("Filter undefined for key %d.", key));
					 return null;
		}
	}
	
	public Filter(float[] filter) {
		this.filter = filter;
		this.size = (int) Math.sqrt(this.filter.length);
	}
	
	public Filter(int size) {
		int i, j;
		float t;
		this.size = size;
		this.filter = new float[this.size*this.size];
		t = this.size * this.size +1;
		for(i = 0; i < this.size; i++)
			for(j = 0; j < this.size; j++)
				if(i == this.size/2 && j == this.size/2)
					this.filter[i*this.size+j] = (float) (2.0/t);
				else
					this.filter[i*this.size+j] = (float) (1.0/t);
	}
	
	private void checkResult(float f) {
		if (f < 0)
			f = 0;
		else if (f > 255)
			f = 255;
	}

	public int getSize() {
		return this.size;
	}

	public float[] getFilter() {
		return this.filter;
	}

	public int apply(int[][][] tab, int x, int y) {
		int i, j, k, l, ind;
		float alpha, red, green, blue;
		alpha = red = green = blue = 0.0f;

		l = 0;
		for (j = (y - this.size / 2); j < (y + this.size / 2 + 1); j++) {
			k = 0;
			for (i = (x - this.size / 2); i < (x + this.size / 2 + 1); i++) {
				ind = l * this.size + k;
				alpha += this.filter[ind] * tab[i][j][0];
				red += this.filter[ind] * tab[i][j][1];
				green += this.filter[ind] * tab[i][j][2];
				blue += this.filter[ind] * tab[i][j][3];
				k++;
			}
			l++;
		}

		checkResult(alpha);
		checkResult(red);
		checkResult(green);
		checkResult(blue);

		return ((int) alpha << 24) + ((int) red << 16) + ((int) green << 8) + (int) blue;
	}
}
